package com.zsx.shopping.ware.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsx.shopping.common.api.order.enums.OrderStatus;
import com.zsx.shopping.common.api.order.feign.OrderFeignService;
import com.zsx.shopping.common.api.ware.dto.LockStockDto;
import com.zsx.shopping.common.exception.ShoppingException;
import com.zsx.shopping.ware.entity.OrderStockTask;
import com.zsx.shopping.ware.entity.OrderStockTaskItem;
import com.zsx.shopping.ware.enums.LockStatus;
import com.zsx.shopping.ware.mapper.OrderStockTaskItemMapper;
import com.zsx.shopping.ware.mapper.WareSkuStockMapper;
import com.zsx.shopping.ware.service.OrderStockTaskService;
import com.zsx.shopping.ware.mapper.OrderStockTaskMapper;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;

/**
 *
 */
@Service
public class OrderStockTaskServiceImpl extends ServiceImpl<OrderStockTaskMapper, OrderStockTask>
    implements OrderStockTaskService{

    @Resource
    private OrderFeignService orderFeignService;

    @Resource
    private OrderStockTaskMapper orderStockTaskMapper;

    @Resource
    private WareSkuStockMapper wareSkuStockMapper;

    @Resource
    private OrderStockTaskItemMapper orderStockTaskItemMapper;

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Transactional
    @Override
    public void lockStock(LockStockDto lockStockDto) {
        // 保存库存工作单
        OrderStockTask orderStockTask = new OrderStockTask();
        orderStockTask.setOrderId(lockStockDto.getOrderId());
        orderStockTask.setLockStatus(LockStatus.LOCKED.getCode());
        orderStockTask.setOrderSn(lockStockDto.getOrderSn());
        orderStockTaskMapper.insert(orderStockTask);

        Long taskId = orderStockTask.getId();
        lockStockDto.getItems().forEach(lockStockItemDto -> {
            Long skuId = lockStockItemDto.getSkuId();
            Integer skuNum = lockStockItemDto.getSkuNum();
            // 查询有库存的仓库列表
            List<Long> wareIds = wareSkuStockMapper.getWareIdsHasStock(skuId, skuNum);
            boolean success = false;
            for (Long wareId : wareIds) {
                if(wareSkuStockMapper.lockStock(skuId, skuNum, wareId) > 0) {
                    // 该商品(订单项)锁定库存成功
                    success = true;
                    // 保存库存工作单条目
                    OrderStockTaskItem orderStockTaskItem = new OrderStockTaskItem();
                    orderStockTaskItem.setTaskId(taskId);
                    orderStockTaskItem.setSkuNum(skuNum);
                    orderStockTaskItem.setSkuId(skuId);
                    orderStockTaskItem.setWareId(wareId);
                    orderStockTaskItemMapper.insert(orderStockTaskItem);
                    break;
                }
            }
            if (!success) {
                // 所有仓库都没该商品库存,整个订单锁库存失败,抛出异常回滚
                throw new ShoppingException("商品【" + lockStockItemDto.getSkuName() + "】库存不足");
            }
        });

        // 订单(包括所有订单项)锁定库存成功
        // 发送订单id至RabbitMQ延时队列,若订单服务发生异常,则到期自动解库存,实现分布式事务
        rabbitTemplate.convertAndSend(
                "stock-event-exchange",
                "stock.locked",
                lockStockDto.getOrderId());
    }

    @Override
    public void releaseStock(Long orderId) {
        Byte status = orderFeignService.getOrderStatus(orderId).getData();
        if (status == null || OrderStatus.CANCEL.getCode().equals(status)
                || OrderStatus.CLOSED.getCode().equals(status)) {
            OrderStockTask orderStockTask = orderStockTaskMapper.selectOne(new LambdaQueryWrapper<OrderStockTask>()
                    .eq(OrderStockTask::getOrderId, orderId));
            if (LockStatus.LOCKED.getCode().equals(orderStockTask.getLockStatus())) {
                wareSkuStockMapper.releaseStock(orderId);
                orderStockTask.setLockStatus(LockStatus.RELEASE.getCode());
                orderStockTaskMapper.updateById(orderStockTask);
            }
        }
    }

    @Override
    public void reduceStock(Long orderId) {
        OrderStockTask orderStockTask = orderStockTaskMapper.selectOne(
                new LambdaQueryWrapper<OrderStockTask>().eq(OrderStockTask::getOrderId, orderId));
        if (LockStatus.LOCKED.getCode().equals(orderStockTask.getLockStatus())) {
            wareSkuStockMapper.reduceStock(orderId);
            orderStockTask.setLockStatus(LockStatus.REDUCE.getCode());
            orderStockTaskMapper.updateById(orderStockTask);
        }
    }
}




